const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const Schema = mongoose.Schema;
const { ObjectId, Mixed } = Schema.Types; // Mixed 混合类型
const SALT_WORK_FACTOR = 10; // 加密等级，越大越好
const MAX_LOGIN_ATTEMPTS = 5; // 最大输错密码次数，大于该次数，锁定账户
const LOCK_TIME = 2 * 60 * 60 * 1000; // 锁定账户时间（毫秒）

const userSchema = new Schema({
    username: {  // 登录的用户名（QQ号）
        unique: true,
        required: true,
        type: String,
    },
    userType: {
        type: String,
        default: "common"  //  common，vip，agent，admin，boss
    },
    of_name: String,  // 收货人姓名（张三）
    of_phone: String,  // 收货人手机
    of_tailNumber: String, // 收货手机尾号
    of_address: String,  // 送货地址（明泽苑3号楼）
    joinTimestamp: Number,
    meta: {
        createdAt: {
            type: Date,
            default: Date.now()
        },
        updatedAt: {
            type: Date,
            default: Date.now()
        }
    }
});

// 虚拟字段
userSchema.virtual('isLocked').get(function () {
    return !!(this.lockUntil && this.lockUntil > Date.now())
});

userSchema.pre('save', function (next) {
    if (this.isNew) {
        this.meta.createdAt = this.meta.updatedAt = Date.now()
    } else {
        this.meta.updatedAt = Date.now()
    }

    next()
});

userSchema.pre('save', function (next) {
    // 查看某字段是否被更改
    if (!this.isModified('password')) return next();

    // 加密
    bcrypt.genSalt(SALT_WORK_FACTOR, (err, salt) => {
        if (err) return next(err);

        bcrypt.hash(this.password, salt, (error, hash) => {
            if (error) return next(error);

            // 替换密码为加密后的密码
            this.password = hash;
            next()
        })
    })
});

// 一些实例方法
userSchema.methods = {
    // 密码比对
    comparePassword: (_password, password) => {
        return new Promise((resolve, reject) => {
            // _password 是输入的密码 password 是数据库存入的加密后的密码 isMatch 是一个布尔值，是否匹配
            bcrypt.compare(_password, password, (err, isMatch) => {
                if (!err) resolve(isMatch);
                else reject(err)
            })
        })
    },

    // 判断用户是否超过最大试错次数
    incLoginAttepts: (user) => {
        return new Promise((resolve, reject) => {
            // 当前账户已被锁定，但锁定时期已过，（当前未被锁定）
            if (this.lockUntil && this.lockUntil < Date.now()) {
                // 更新字段
                this.update({
                    $set: {
                        loginAttempts: 1
                    },
                    $unset: {
                        lockUntil: 1
                    }
                }, (err) => {
                    if (!err) resolve(true)
                    else reject(err)
                })
            } else {
                let updates = {
                    $inc: {
                        loginAttempts: 1 // +1
                    }
                }

                // 当前账户为被锁定，且尝试登录次数大于最大试错次数
                if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked) {
                    // 为当前账户设置锁定
                    updates.$set = {
                        lockUntil: Date.now() + LOCK_TIME
                    }
                }

                // 修改字段值
                this.update(updates, err => {
                    if (!err) resolve(true)
                    else reject(err)
                })
            }
        })
    }
};

mongoose.model('User', userSchema);